home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / util2 / stpprg20.zip / STOPPRG.ASM next >
Assembly Source File  |  1993-03-05  |  34KB  |  853 lines

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;  StopPrg, by MAK-TRAXON's Prophet                                        ;;
  3. ;;  Started October 1992                                                    ;;
  4. ;;  Version 2.0 : latest update: 27/2/1993                                  ;;
  5. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  6.  
  7. progseg         segment public
  8.                 assume cs:progseg,ss:progseg,es:progseg,ds:progseg
  9.                 page 60,80
  10.                 org 100h
  11.                 ; MASM-compatible header for .COM file
  12.  
  13. wo              equ word ptr
  14. by              equ byte ptr
  15. dwo             equ dword ptr
  16. jmps            equ jmp short
  17.                 ; some handy shortcuts
  18.  
  19. entpt:          jmp install     ; jump to init routines
  20.  
  21. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ABOUT STOPPRG ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  22.  
  23. ; StopPrg was started about October 1992 by MAK-TRAXON's Prophet at the
  24. ; Club Info of the Lycee Louis-le-Grand. Its 1st version recognized the hot
  25. ; key LeftShift - RightShift to either exit to DOS or hang the computer.
  26. ; Saving a copy of the interrupt table and avoiding to interrupt an int 9
  27. ; helped to make StopPrg exit to DOS more often than hang the computer.
  28. ; It was also made possible to choose the hot key among combinations of Shifts
  29. ; Ctrl and Alt. This worked OK except with games and uncivilised programs which
  30. ; take int 9 witout chaining it; they would simply ignore StopPrg.
  31. ;
  32. ; This new version has been specifically designed to insist taking int 9 up
  33. ; to 10 times, even in the middle of the execution of a program, so that it
  34. ; can always have control over int 9. The hot key has been changed to Alt -
  35. ; Ctrl - Enter, and can no longer be changed except by recompiling, and the
  36. ; /M (maximum compatibility) command line option has been added. With this
  37. ; option, int 9 will not be taken more than once.
  38. ;
  39. ; How does StopPrg work? The idea is simple: it takes int 9, reads the keyboard
  40. ; and when Alt - Ctrl - Enter is pressed, issues an Int 21h with ah = 4ch.
  41. ; To have this work reliably, it must also take a number of precautions: every
  42. ; time a program is executed, StopPrg saves a copy of the entire interrupt
  43. ; table, to restore it when it activates. This allows to exit from programs
  44. ; which take interrupts during their execution, and restore them afterwards.
  45. ; StopPrg also avoids activating during a disk access (that is during an 
  46. ; int 13h), and less than 3 seconds after the last activation. To be able to
  47. ; take int 9 more than once, it must have a number of int 9 entry points or
  48. ; slots (10 in this version), and a way to free them when the program which
  49. ; used a slot has restored its interrupt; this is done when a program exits
  50. ; to DOS using int 20h, int 27h or int 21h functions 0, 4ch or 31h.
  51. ;
  52. ; There are some particular conditions where StopPrg is not so reliable:
  53. ; when the EXEC function (4b00h) has been used in chain by several programs
  54. ; (DOS shelling from applications), StopPrg can only reliably be used once
  55. ; to exit from the "topmost" program. This happens because when the topmost
  56. ; program was loaded StopPrg saved the interrupt table, so when it exits
  57. ; it can no longer restore the interrupt table corresponding to before the
  58. ; next program was loaded. This is of course no problem if these programs did
  59. ; not alter the interrupt table.
  60. ;
  61. ; Also activating StopPrg from a Pop-Up resident is not reliable and cannot be
  62. ; recommended; if the Pop-Up did not activate its PSP this will probably exit
  63. ; the current application as well as the Pop-Up, possibly leaving the Pop-Up
  64. ; in an unstable state. If it did, and no other program has been executed
  65. ; in between, then StopPrg should restore the interrupt table, effectively
  66. ; disabling the Pop-Up, and the DOS Exit function executed with the Pop-Up's
  67. ; PSP active should even free its memory! (I tried this with my Resident Norton
  68. ; Editor, and it worked!)
  69. ; Also activating StopPrg from the DOS prompt will restore the interrupt table,
  70. ; and this will disable the last program if it was a TSR, without freeing its
  71. ; memory. If it was not a TSR, then StopPrg will do little more than Cls
  72. ; (this is safe but typing Cls is still safer !).
  73. ;
  74. ; An unwanted effect of StopPrg's taking int 9 more than once is that if a TSR
  75. ; is loaded after StopPrg, and it takes int 9 (most TSRs do), then int 9 will
  76. ; appear to have been taken again, so the resident will refuse to uninstall
  77. ; (or only disable itself without freeing its memory or restoring its
  78. ; interrupt vectors). To correct this, StopPrg will attempt to catch the
  79. ; uninstalling program reading the interrupt table and, if StopPrg has taken
  80. ; int 9 more than once, it will give the last int 9 vector instead of its own
  81. ; slot address. This works as long as the uninstalling program uses DOS
  82. ; function 35h to read an interrupt vector, instead of reading directly at 
  83. ; 0000:00024h. This should also make that, when a TSR is installed after
  84. ; StopPrg, StopPrg will only once check if its hot-key has been pressed
  85. ; instead of doing it as many times as it has taken int 9 (this makes no
  86. ; practial difference, and applies only if the TSR uses the DOS to read the
  87. ; interrupt table).
  88. ;
  89. ; Finally, a word about SideKick compatibility: SideKick versions 1.x has
  90. ; a bug in it. It takes int 9, and if int 9 is taken by some other program, 
  91. ; it will take it again at the next clock tick, making it point to a secondary
  92. ; handler which only checks the shift state and stores it in a variable. Now
  93. ; if a resident program, when SideKick has already done this, takes int 9 again
  94. ; (this can happen if a game using int 9 is loaded after a resident which uses
  95. ; it too), SideKick will take it again (3rd time!) and make it point to the
  96. ; SAME handler. So the second return address will be lost, and int 9 will 
  97. ; recurse, hopelessly hanging the computer (try it!). Since StopPrg uses a
  98. ; similar technique to take int 9 up to 10 times, it would be sure to be
  99. ; incompatible with SideKick. The solution: find SideKick in memory, and poke
  100. ; a byte to disable taking int 9 more than once. This works (i.e the computer
  101. ; does not hang and both StopPrg and SideKick respond to their keys) at least
  102. ; with SideKick version 1.56A, and should not change between versions 1.x,
  103. ; since no absolute addresses are used. In any case, if some resident prog
  104. ; does not seem to work with StopPrg, try loading StopPrg after the resident,
  105. ; and if it still does not work, use the /M option.
  106.  
  107. ;;;;;;;;;;;;;;;;;;;;;;;;;;;; MORE ABOUT STOPPRG ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  108.  
  109. ; StopPrg's internal programmer interface:
  110. ;  * checking whether StopPrg is loaded: issue an Int 21h with AX = 3022h.
  111. ;    DOS will give you AX = version number, and StopPrg will put
  112. ;    CX = 1112h and BX = segment where StopPrg is loaded
  113. ;  * telling StopPrg not to activate: put the value 9090h in 0:4feh
  114. ;    (in the Inter-Application-Communication-Area)  (Somebody had to use it
  115. ;    one day!).
  116. ;    Remember to restore the previous value (or set it to 0) on exit.
  117.  
  118. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CONSTANTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  119.  
  120. nb_slots        = 10            ; number of int 9 slots
  121.  
  122. ;;;;;;;;;;;;;;;;;;;;;;;;;;;; RESIDENT DATA ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  123.  
  124. old8            label dword     ; saved int 8 vector
  125.                 db 01ah,0,0,0   ; 4 bytes
  126. old20           dd 0            ; saved int 20h vector
  127. old27           dd 0            ; saved int 27h vector
  128. old13           dd 0            ; saved int 13h vector
  129. out9            dd 0            ; address where to jmp to give control from
  130.                                 ; an int 9
  131. old21           dd 0            ; saved int 21 vector
  132. dosavail        dd 0            ; address of InDos flag
  133. in13            db 0            ; flag: is an int 13h in execution ?
  134. jdone           db 0            ; flag: has StopPrg just been activated ?
  135.                                 ; Set to 36 by a StopPrg activation,
  136.                                 ; decremented by Int 8, and StopPrg will not
  137.                                 ; activate if it is not 0.
  138. ints            db 400h dup (0) ; copy of the interrupt table
  139.                                 ; (restored at exit)
  140. nomsg           db 0            ; flag: were we asked not to print any messages
  141.                                 ; unless something goes wrong ?
  142. un_inst         db 0            ; flag: were we asked to uninstall ?
  143. soft            db 0            ; flag: were we asked to use "very compatible"
  144.                                 ; interrupt handlings ?
  145. ctrl            db 0            ; flag: set to 36 by int 9 when Ctrl is pressed
  146.                                 ; decremented by int 8
  147. alt             db 0            ; same thing with Alt
  148. slot            db 0            ; which is the last int 9 slot that has been
  149.                                 ; used ?
  150. old9            label dword
  151. slots           dd nb_slots dup (0)
  152.  
  153. ;;;;;;;;;;;;;;;;;;;;;;;;;;;; INTERRUPT HANDLERS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  154.  
  155. ; the different int 9 slots
  156.  
  157. new9            label near      ; address of first slot
  158.                 which_slot = 0
  159. slot_0          label near
  160.                 rept nb_slots   ; assembler directive: assemble nb_slots times
  161.                 local start_slot
  162. start_slot:     push ax
  163.                 mov al,which_slot
  164.                 jmps int_9
  165.                 slot_len = $ - offset start_slot   ; used later
  166.                 which_slot = which_slot + 1
  167.                 endm            ; end of loop
  168.  
  169. ; generic int 9 handler: AL = slot number (used for Exit), AX has been pushed
  170.  
  171. int_9:          sti
  172.                 push ax
  173.                 in al,60h       ; get scan code
  174.                 cmp al,29       ; Ctrl
  175.                 jnz noctrl
  176.                 mov by cs:ctrl,36
  177.                 jmps cont9
  178.                 
  179. noctrl:         cmp al,29+80h   ; Ctrl released?
  180.                 jnz noctrl2
  181.                 mov by cs:ctrl,0
  182.                 jmps cont9
  183.  
  184. noctrl2:        cmp al,56       ; Alt
  185.                 jnz noalt
  186.                 mov by cs:alt,36
  187.                 jmps cont9
  188.  
  189. noalt:          cmp al,56+80h   ; Alt released?
  190.                 jnz noalt2
  191.                 mov by cs:alt,0
  192.                 jmps cont9
  193.  
  194. noalt2:         cmp al,28       ; Cr
  195.                 jnz cont9
  196.                 cmp by cs:alt,0
  197.                 jz cont9
  198.                 cmp by cs:ctrl,0
  199.                 jz cont9
  200.                 cmp by cs:jdone,0
  201.                 jnz cont9
  202.                 cmp by cs:in13,0  ; activation if Cr was the key, Alt and Ctrl
  203.                 jnz cont9         ; were already down, and jdone=in13=0
  204.                 push ds
  205.                 xor ax,ax
  206.                 mov ds,ax
  207.                 cmp wo ds:[4feh],9090h
  208.                 pop ds
  209.                 jnz hot_key
  210.  
  211. cont9:          pop ax          ; AL = slot number
  212.  
  213.                 push bx         ; save BX
  214.                 xor ah,ah
  215.                 add ax,ax
  216.                 add ax,ax
  217.                 mov bx,ax
  218.                 add bx,offset slots    ; [BX] = address to jump
  219.                 cli
  220.                 mov ax,cs:[bx]
  221.                 mov wo cs:out9,ax
  222.                 inc bx
  223.                 inc bx
  224.                 mov ax,cs:[bx]
  225.                 mov wo cs:out9[2],ax   ; copy it to out9 (to free BX)
  226.                 pop bx
  227.                 pop ax          ; pushed by each slot
  228.                 jmp dwo cs:out9 ; give back control
  229.  
  230. hot_key:        push cs             ; if it was ...
  231.                 pop ds              ; ds = cs
  232.                 mov by jdone,36     ; set the "activated" flag
  233.                 les bx,dosavail
  234.                 mov by es:[bx],0    ; set InDos to zero (tell the DOS it is
  235.                                     ; not doing anything; if it was doing
  236.                                     ; something it's lost anyway ...)
  237.  
  238.                 in al,61h
  239.                 mov ah,al
  240.                 or al,80h
  241.                 out 61h,al
  242.                 mov al,ah
  243.                 out 61h,al          ; tell the kbd controller that we're done
  244.                 mov al,20h
  245.                 out 20h,al          ; same thing to the interrupt controller
  246.  
  247.                 cli                 ; disable interrupts
  248.  
  249.                 xor ax,ax
  250.                 mov ds,ax           ; ds = 0
  251.  
  252.                 push wo ds:[88h]
  253.                 push wo ds:[8ah]
  254.                 push wo ds:[8ch]
  255.                 push wo ds:[8eh]
  256.                 push wo ds:[90h]    ; save int 22, 23, 24 vectors
  257.                 push wo ds:[92h]    ; (needed by DOS for Exit)
  258.  
  259.                 push ds
  260.                 pop es
  261.                 push cs
  262.                 pop ds
  263.  
  264.                 mov si,offset ints
  265.                 xor di,di
  266.                 mov cx,200h
  267.                 cld
  268.                 rep movsw           ; copy saved interrupt table to 0:0
  269.  
  270.                 xor ax,ax
  271.                 mov ds,ax
  272.  
  273.                 pop wo ds:[92h]
  274.                 pop wo ds:[90h]
  275.                 pop wo ds:[8eh]
  276.                 pop wo ds:[8ch]
  277.                 pop wo ds:[8ah]     ; recover int 22, 23 and 24 handlers
  278.                 pop wo ds:[88h]     ; (needed by DOS for Exit)
  279.  
  280.                 sti                 ; enable interrupts
  281.  
  282.                 in al,61h
  283.                 and al,0feh
  284.                 out 61h,al          ; disable the speaker
  285.  
  286.                 mov al,36h
  287.                 out 43h,al
  288.                 mov al,0
  289.                 out 40h,al          ; set the standard int 8 rate
  290.                 out 40h,al          ; (many games change it)
  291.  
  292.                 mov al,by ds:[449h] ; get video mode
  293.                 cmp al,7
  294.                 jz contvmode
  295.                 mov al,3
  296. contvmode:      xor ah,ah           ; set it to 7 if it was 7, else set
  297.                 int 10h             ; it to 3
  298.  
  299.                 push cs
  300.                 pop ds
  301.                 push cs
  302.                 pop es
  303.  
  304.                 mov ax,4c77h
  305.                 int 21h             ; exit to DOS
  306.  
  307. ; Interrupt 8 (timer) handler
  308.  
  309. new8:           cmp by cs:jdone,0  ; has StopPrg recently activated ?
  310.                 jz nojdn
  311.                 dec by cs:jdone    ; if so, decrement flag ...
  312.  
  313. nojdn:          cmp by cs:ctrl,0   ; was Ctrl recently pressed ?
  314.                 jz noctr
  315.                 dec by cs:ctrl     ; if so dec flag ...
  316.  
  317. noctr:          cmp by cs:alt,0    ; was Alt recently pressed ?
  318.                 jz noal
  319.                 dec by cs:alt      ; if so dec flag ...
  320.  
  321. noal:           cmp by cs:soft,0   ; do we have to be soft & compatible ?
  322.                 jnz exit8          ; if so, exit
  323.  
  324.                 push es
  325.                 push ax
  326.                 push bx
  327.                 push cx
  328.  
  329.                 mov al,8
  330.                 call readint       ; read int 8 vector
  331.                 cmp wo es:[bx+1dh],0a1fah
  332.                 jnz nosdk
  333.                 cmp wo es:[bx+1fh],26h
  334.                 jnz nosdk
  335.                 cmp wo es:[bx+25h],74c3h
  336.                 jnz nosdk          ; is SideKick hooked on int 8 ?
  337.  
  338.                 mov by es:[bx+26h],0ebh
  339.                                    ; if so, poke a byte in its code
  340.  
  341. ; SideKick has a bug in it: if int 9 is stolen from it, it will take it again,
  342. ; making it point to a secondary int 9 handler. However, if this happens more
  343. ; than once, the resulting int 9 handler will recurse, hanging the system.
  344. ; since StopPrg will take int 9 up to 10 times, this would be sure to hang
  345. ; SideKick. We simply disable this (bugged) feature.
  346.  
  347. nosdk:          mov al,9
  348.                 call readint       ; read int 9 vector
  349.                 mov ax,es
  350.                 mov cx,cs          ; if segment = cs => exit (nothing to do)
  351.                 cmp ax,cx
  352.                 jz ok9
  353.                 cmp by cs:slot,nb_slots-1
  354.                 jnb ok9            ; if all the slots are taken, exit
  355.  
  356.                 push ds
  357.                 push dx
  358.                 
  359.                 push cs
  360.                 pop ds
  361.                 inc by slot
  362.                 mov cx,bx       ; ES:CX = int 9 to save
  363.                 mov bl,slot
  364.                 xor bh,bh
  365.                 add bx,bx
  366.                 add bx,bx       ; CS:slots[BX] = where to save int 9 handler
  367.                 mov wo slots[bx],cx
  368.                 mov wo slots[bx][2],es
  369.                 mov al,slot
  370.                 mov ah,slot_len
  371.                 mul ah
  372.                 add ax,offset new9
  373.                 mov dx,ax
  374.                 mov al,9
  375.                 call setint
  376.  
  377.                 pop dx
  378.                 pop ds
  379.  
  380. ok9:            pop cx
  381.                 pop bx
  382.                 pop ax
  383.                 pop es
  384.  
  385. exit8:          jmp dwo cs:old8    ; jmp to org int 8 handler
  386.  
  387. ; Interrupt 21 (DOS) handler
  388.  
  389. new21:          cmp ax,4b00h    ; is function 4b00 ? (exec program)
  390.                 jz func4b       ; if so, handle it in func4b
  391.  
  392.                 cmp ah,0        ; is function 0 ... (exit to DOS)
  393.                 jz exitDOS
  394.                 cmp ah,4ch      ; or function 4ch ... (exit with errorlevel)
  395.                 jz exitDOS
  396.                 cmp ah,31h      ; or function 31h ? (TSR)
  397.                 jnz noexitDOS
  398.  
  399. exitDOS:        call recalc     ; if so, recalculate slot
  400.                 jmps exit21
  401.  
  402. noexitDOS:      cmp ax,3022h    ; is function 30h (get version), with
  403.                                 ; special code 22h in AL ?
  404.                 jnz noack       ; if so,
  405.                 pushf
  406.                 call dwo cs:old21    ; call original int 21h handler
  407.                 mov cx,1112h    ; return acknowledgement code (1112h in CX)
  408.                 mov bx,cs       ; return program segment in BX
  409.                 iret
  410.  
  411. noack:          cmp ax,3509h    ; is function 35h (read int vector) with AL=9 ?
  412.                 jnz exit21      ; if not, exit
  413.                 cmp cs:slot,0   ; if slot is 0 (the 1st one)
  414.                 jz exit21
  415.                 cmp cs:slot,nb_slots-1
  416.                 jz exit21       ; or nb_slots-1 (the last one) then exit
  417.                 mov bl,cs:slot
  418.                 xor bh,bh
  419.                 add bx,bx
  420.                 add bx,bx
  421.                 add bx,offset slots
  422.                 les bx,cs:[bx]  ; return (in ES:BX) the current slot's return
  423.                                 ; address
  424.                 iret
  425.  
  426. exit21:         jmp dwo cs:old21     ; jump to original int 21h handler
  427.  
  428. func4b:         call recalc     ; recalculate slot number
  429.                 push ax
  430.                 push ds
  431.                 push es
  432.                 push si
  433.                 push di
  434.                 push cx         ; save registers
  435.  
  436.                 xor ax,ax
  437.                 mov ds,ax
  438.                 push cs
  439.                 pop es
  440.                 xor si,si
  441.                 mov di,offset ints
  442.                 mov cx,200h
  443.                 cld
  444.                 rep movsw       ; copy interrupt table to the "ints" buffer
  445.  
  446.                 pop cx
  447.                 pop di
  448.                 pop si
  449.                 pop es
  450.                 pop ds
  451.                 pop ax          ; restore saved registers
  452.  
  453.                 jmp exit21      ; jmp to original int 21h handler
  454.  
  455. new20:          call recalc     ; recalculate slot
  456.                 jmp dwo cs:old20; jmp to original int 20h handler
  457.  
  458. new27:          call recalc     ; recalculate slot
  459.                 jmp dwo cs:old27; jmp to original int 27h handler
  460.  
  461. new13:          mov cs:in13,1   ; set flag
  462.                 pushf
  463.                 call dwo cs:old13  ; call original int 13h
  464.                 mov cs:in13,0   ; reset flag
  465.                 sti
  466.                 retf 2          ; return preserving flags
  467.  
  468. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RESIDENT PROCEDURES ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  469.  
  470. recalc          proc
  471. ; recalculate slot : if int 9 is pointing to StopPrg, "slot" is the slot
  472. ; number to which it is pointing (free slots whose interrupts have been
  473. ; released by other programs)
  474.                 cmp by cs:soft,0 ; are we soft ?
  475.                 jnz exit_recalc  ; if so, nothing to do (slot is always 0)
  476.                 push ax
  477.                 push bx
  478.                 push cx
  479.                 push es         ; save registers
  480.                 mov al,9
  481.                 call readint    ; read int 9 vector
  482.                 mov cx,es
  483.                 mov ax,cs
  484.                 cmp ax,cx       ; is it pointing to StopPrg ?
  485.                 jnz end_recalc  ; if not, exit
  486.                 mov ax,bx
  487.                 sub ax,offset new9  ; get offset of slot (int 9 entry point)
  488.                 cmp ax,(nb_slots-1)*slot_len
  489.                                 ; is it within the int 9 entry point table ?
  490.                 ja end_recalc   ; if not, exit
  491.                 mov bl,slot_len
  492.                 div bl          ; calc slot number
  493.                 mov cs:slot,al  ; set slot number
  494.  
  495. end_recalc:     pop es
  496.                 pop cx
  497.                 pop bx
  498.                 pop ax          ; restore regs
  499. exit_recalc:    ret
  500. recalc          endp
  501.  
  502. readint         proc
  503. ; AL = int number  =>  ES:BX = interrupt handler
  504.                 xor bx,bx
  505.                 mov es,bx
  506.                 mov bl,al
  507.                 add bx,bx
  508.                 add bx,bx
  509.                 les bx,es:[bx]
  510.                 ret
  511. readint         endp
  512.  
  513. setint          proc
  514. ; AL= int number, DS:DX = new int handler
  515.                 push es
  516.                 push bx
  517.                 xor bx,bx
  518.                 mov es,bx
  519.                 mov bl,al
  520.                 add bx,bx
  521.                 add bx,bx
  522.                 cli
  523.                 mov es:[bx],dx
  524.                 mov es:[bx+2],ds
  525.                 sti
  526.                 pop bx
  527.                 pop es
  528.                 ret
  529. setint          endp
  530.  
  531. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; INITIALISATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  532.  
  533. install:        mov si,81h      ; address of command line tail
  534.                 cld
  535. loopchar:       lodsb           ; get a char
  536.                 cmp al,' '
  537.                 jz loopchar
  538.                 cmp al,9
  539.                 jz loopchar     ; skip spaces and TABs
  540.                 cmp al,'/'
  541.                 jz loopchar     ; skip slashes
  542.                 cmp al,'-'
  543.                 jz loopchar     ; skip hyphens (alias for /)
  544.                 and al,0dfh     ; convert to uppercase
  545.                 cmp al,'U'      ; if it is U ...
  546.                 jnz nou
  547.                 inc un_inst     ; set the UnInstall flag
  548.                 jmps loopchar
  549. nou:            cmp al,'N'      ; if it is N
  550.                 jnz non
  551.                 inc nomsg       ; then put the NoMsg flag on
  552.                 jmps loopchar
  553. non:            cmp al,'M'      ; if it is M
  554.                 jnz nom
  555.                 inc soft        ; then put the "soft" flag on
  556.                 jmps loopchar
  557. nom:            cmp al,0dh      ; if it is Cr
  558.                 jz endcmd       ; then we are done
  559.  
  560.                 ; if we are here, some unrecognized letter was found
  561.  
  562.                 mov ah,9
  563.                 mov dx,offset messprg
  564.                 int 21h         ; display prog name and info
  565.                 mov ah,9
  566.                 mov dx,offset messwrongcmd
  567.                 int 21h         ; complain
  568.                 mov ax,4c01h
  569.                 int 21h         ; exit to DOS
  570.  
  571. endcmd:         cmp nomsg,0
  572.                 jnz no_msg1
  573.                 mov ah,9
  574.                 mov dx,offset messprg ; display prg name and info unless
  575.                 int 21h               ; asked not to do it
  576. no_msg1:        cmp un_inst,0
  577.                 jnz uninstall
  578.                 jmp nouninst    ; jmp to nouninst if not asked to uninstall
  579.  
  580. ;               StopPrg has been asked to uninstall from memory
  581. uninstall:      mov ax,3022h
  582.                 int 21h         ; is it already there ?
  583.                 cmp cx,1112h
  584.                 jz noerr1
  585.  
  586.                 call progname   ; disp. prog name even if asked not to do it
  587.                                 ; (before complaining)
  588.                 mov ah,9
  589.                 mov dx,offset messerrnoinst
  590.                 int 21h
  591.                 mov ax,4c01h    ; if not, complain and exit to DOS
  592.                 int 21h
  593.  
  594. noerr1:         mov bp,bx
  595.                 mov es,bp       ; ES = BP = segment of resident StopPrg
  596.                 cmp es:slot,0   ; is the resident StopPrg in its first slot ?
  597.                 jz noerr2
  598.                 call progname   ; if not so, disp. prog name even if asked not
  599.                                 ; to do it
  600.                 mov ah,9
  601.                 mov dx,offset messerrslots
  602.                 int 21h         ; then complain
  603.                 mov ax,4c01h
  604.                 int 21h         ; and exit to DOS
  605.  
  606. noerr2:         mov al,20h
  607.                 call readint
  608.                 mov ax,es
  609.                 cmp ax,bp
  610.                 jnz err3        ; is int 20h pointing to the resident StopPrg ?
  611.                 mov al,13h
  612.                 call readint
  613.                 mov ax,es
  614.                 cmp ax,bp
  615.                 jnz err3        ; is int 13h pointing to the resident StopPrg ?
  616.                 mov al,27h
  617.                 call readint
  618.                 mov ax,es
  619.                 cmp ax,bp
  620.                 jnz err3        ; is int 27h pointing to the resident StopPrg ?
  621.                 mov al,21h
  622.                 call readint
  623.                 mov ax,es
  624.                 cmp ax,bp
  625.                 jnz err3        ; is Int 21h pointing to the resident StopPrg ?
  626.                 mov al,9
  627.                 call readint
  628.                 mov ax,es
  629.                 cmp ax,bp
  630.                 jnz err3        ; is Int 9h pointing to the resident StopPrg ?
  631.                 mov al,8
  632.                 call readint
  633.                 mov ax,es
  634.                 cmp ax,bp
  635.                 jz noerr3       ; is Int 8h pointing to the resident StopPrg ?
  636.  
  637. err3:           call progname   ; disp. prog name even if asked not to do it
  638.                                 ; (before complaining)
  639.                 mov ah,9
  640.                 mov dx,offset messerrothers
  641.                 int 21h
  642.                 mov ax,4c01h    ; if not so, complain and exit to DOS
  643.                 int 21h
  644.  
  645. noerr3:         mov es,bp
  646.                 lds dx,es:old8  ; restore Int 8h vector
  647.                 mov al,8
  648.                 call setint
  649.                 lds dx,es:old9  ; restore Int 9h vector
  650.                 mov al,9
  651.                 call setint
  652.                 lds dx,es:old13 ; restore Int 13h vector
  653.                 mov al,13h
  654.                 call setint
  655.                 lds dx,es:old21 ; restore Int 21h vector
  656.                 mov al,21h
  657.                 call setint
  658.                 lds dx,es:old20 ; restore Int 20h vector
  659.                 mov al,20h
  660.                 call setint
  661.                 lds dx,es:old27 ; restore Int 27h vector
  662.                 mov al,27h
  663.                 call setint     ; (we are accessing the resident StopPrg's
  664.                                 ; variables)
  665.  
  666.                 push cs
  667.                 pop ds
  668.  
  669.                 mov ah,49h      ; free the resident StopPrg's segment
  670.                 int 21h
  671.  
  672.                 cmp nomsg,0
  673.                 jnz no_msg2
  674.                 mov ah,9
  675.                 mov dx,offset messuninstok
  676.                 int 21h         ; if not asked to shut up ...
  677. no_msg2:        mov ax,4c00h    ; say everything OK and exit to DOS
  678.                 int 21h
  679.  
  680. ; we were asked to install
  681. nouninst:       mov ah,34h
  682.                 int 21h
  683.                 mov wo dosavail,bx
  684.                 mov wo dosavail[2],es           ; get InDos Ptr
  685.  
  686.                 mov es,wo cs:[2ch]              ; free our own environment
  687.                 mov ah,49h
  688.                 int 21h
  689.  
  690.                 mov ax,3022h    ; is StopPrg already installed ?
  691.                 int 21h
  692.                 cmp cx,1112h
  693.                 jnz notyet
  694.                 jmp already     ; if so, jmp to "already"
  695.  
  696. notyet:         push cs
  697.                 pop ds
  698.  
  699.                 mov al,8
  700.                 call readint       ; read int 8 vector
  701.  
  702.                 cmp wo es:[bx+1dh],0a1fah
  703.                 jnz nosdk2
  704.                 cmp wo es:[bx+1fh],26h
  705.                 jnz nosdk2
  706.                 cmp wo es:[bx+25h],74c3h
  707.                 jnz nosdk2         ; is SideKick hooked on int 8 ?
  708.  
  709.                 mov by es:[bx+26h],0ebh
  710.                                    ; if so, poke a byte in its code
  711.                                    ; (see new8 for explanations)
  712.  
  713. nosdk2:         mov al,13h      ; read int 13h vector
  714.                 call readint
  715.                 mov wo old13,bx
  716.                 mov wo old13[2],es
  717.  
  718.                 mov al,13h      ; put new int 13h vector
  719.                 mov dx,offset new13
  720.                 call setint
  721.  
  722.                 mov al,21h      ; read int 21h vector
  723.                 call readint
  724.                 mov wo old21,bx
  725.                 mov wo old21[2],es
  726.  
  727.                 mov al,21h      ; put new int 21h vector
  728.                 mov dx,offset new21
  729.                 call setint
  730.  
  731.                 mov al,9        ; read int 9h vector
  732.                 call readint
  733.                 mov wo old9,bx
  734.                 mov wo old9[2],es
  735.  
  736.                 mov al,9        ; put new int 9h vector
  737.                 mov dx,offset new9
  738.                 call setint
  739.  
  740.                 mov al,8        ; read int 8h vector
  741.                 call readint
  742.                 mov wo old8,bx
  743.                 mov wo old8[2],es
  744.  
  745.                 mov al,8        ; put new int 8h vector
  746.                 mov dx,offset new8
  747.                 call setint
  748.  
  749.                 mov al,20h      ; read int 20h vector
  750.                 call readint
  751.                 mov wo old20,bx
  752.                 mov wo old20[2],es
  753.  
  754.                 mov al,20h      ; put new int 20h vector
  755.                 mov dx,offset new20
  756.                 call setint
  757.  
  758.                 mov al,27h      ; read int 27h vector
  759.                 call readint
  760.                 mov wo old27,bx
  761.                 mov wo old27[2],es
  762.  
  763.                 mov al,27h      ; put new int 27h vector
  764.                 mov dx,offset new27
  765.                 call setint
  766.  
  767.                 xor ax,ax
  768.                 mov ds,ax
  769.                 push cs
  770.                 pop es
  771.                 xor si,si
  772.                 mov di,offset ints
  773.                 mov cx,200h
  774.                 cld
  775.                 rep movsw       ; make a copy of the interrupt table
  776.  
  777.                 push cs
  778.                 pop ds
  779.  
  780.                 cmp nomsg,0
  781.                 jnz noinfo
  782.                 mov ah,9
  783.                 mov dx,offset messhotkey
  784.                 int 21h
  785.  
  786. noinfo:         mov dx,offset install[3]
  787.                 int 27h         ; terminate stay resident
  788.  
  789. ; StopPrg was called when it was already resident
  790. already:        call progname   ; disp. prog name even if asked not to do it
  791.                                 ; (before complaining)
  792.                 mov ah,9
  793.                 mov dx,offset messalready
  794.                 push cs
  795.                 pop ds
  796.                 int 21h         ; say we were already installed
  797.  
  798.                 mov ax,4c01h
  799.                 int 21h         ; exit to DOS
  800.  
  801. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; PROCEDURES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  802.  
  803. progname        proc
  804.                 push cs
  805.                 pop ds          ; in case DS was wrong
  806.                 cmp nomsg,0
  807.                 jz skip_it      ; if nomsg is 0, then it was already printed
  808.                 mov ah,9
  809.                 mov dx,offset messprg
  810.                 int 21h         ; display prog name and info
  811.                 mov nomsg,0     ; so that it will not print it again if
  812.                                 ; called twice
  813. skip_it:        ret
  814. progname        endp
  815.  
  816. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MESSAGES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  817.  
  818. messprg         db 0dh,0ah,' ───────────────────────────────────────────'
  819.                 db 0dh,0ah,'  StopPrg v2.0 (c) by MAK-TRAXON''s Prophet'
  820.                 db 0dh,0ah,'       Exit to DOS from any program !'
  821.                 db 0dh,0ah,' ───────────────────────────────────────────'
  822.                 db 0dh,0ah,'       Syntax: StopPrg [/U] [/N] [/M]'
  823.                 db 0dh,0ah,'        U: UnInstall  N: No messages'
  824.                 db 0dh,0ah,'  M: Maximum compatibility with other TSR''s'
  825.                 db 0dh,0ah,' ───────────────────────────────────────────'
  826.                 db 0dh,0ah,'$'
  827. messerrnoinst   db         '   You can''t UnInstall when it is not even'
  828.                 db 0dh,0ah,'               INSTALLED !!!'
  829.                 db 0dh,0ah,' ───────────────────────────────────────────'
  830.                 db 0dh,0ah,'$'
  831. messerrothers   db         '      You must first remove other TSR''s'
  832.                 db 0dh,0ah,' ───────────────────────────────────────────'
  833.                 db 0dh,0ah,'$'
  834. messuninstok    db         '      StopPrg was correctly uninstalled'
  835.                 db 0dh,0ah,' ───────────────────────────────────────────'
  836.                 db 0dh,0ah,'$'
  837. messalready     db         '       StopPrg was already installed !'
  838.                 db 0dh,0ah,' ───────────────────────────────────────────'
  839.                 db 0dh,0ah,'$'
  840. messhotkey      db         '          Hot Key: Alt - Ctrl - ',11h,'─┘'
  841.                 db 0dh,0ah,' ───────────────────────────────────────────'
  842.                 db 0dh,0ah,'$'
  843. messwrongcmd    db         '     Unrecognized command line option !'
  844.                 db 0dh,0ah,' ───────────────────────────────────────────'
  845.                 db 0dh,0ah,'$'
  846. messerrslots    db         '   Impossible to UnInstall: StopPrg had to'
  847.                 db 0dh,0ah,'   take Int 9 back from some other program'
  848.                 db 0dh,0ah,' ───────────────────────────────────────────'
  849.                 db 0dh,0ah,'$'
  850.  
  851. progseg         ends
  852.                 end entpt
  853.